﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

/* 
 * This is a generic class meant to represent any in-game object, 
 * whether it is a player, an enemy, an obstacle tile, etc. 
 * It's most important role is having a dictionary of Animations to play,
 * which can be summoned by their key (a atring name)
 */
namespace Pulse
{
    class Sprite
    {
        public Texture2D spriteTexture { get; set; }
        public Color color = Color.White;
        public float drawOrder = 0.0f;
        public Vector2 Position;
        public Vector2 PreviousPosition;
        public Vector2 spriteCentre;
        private float sRotation = 0.0f;
        public float scale = 1.0f;
        public bool rotatable { get; set; }
        public bool animating = true;
        public int spriteWidth { get; set; }
        public int spriteHeight { get; set; }

        Dictionary<string, Animation> faAnimations = new Dictionary<string, Animation>();

        string currentAnimation = null;
        
        public Sprite(Texture2D Texture)
        {
            this.spriteTexture = Texture;
            this.rotatable = false;
        }

        public float Rotation
        {
            get { return sRotation; }
            set { sRotation = value; }
        }

        public Animation CurrentFrameAnimation
        {
            get
            {
                if (!string.IsNullOrEmpty(currentAnimation))
                    return faAnimations[currentAnimation];
                else
                    return null;
            }
        }

        public string CurrentAnimation
        {
            get { return currentAnimation; }
            set
            {
                if (faAnimations.ContainsKey(value))
                {
                    currentAnimation = value;
                    faAnimations[currentAnimation].currentFrame = 0;
                    //faAnimations[currentAnimation].frameCount = 0;
                }
            }
        }

        public Vector2 position
        {
            get { return Position; }
            set
            {
                PreviousPosition = Position;
                Position = value;
            }
        }

        /// <summary>
        /// Add a frame of animation to the Dictionary
        /// </summary>
        public void AddAnimation(string Name, int x, int y, int width, int height,
            int framecount, int mapWidth, float frametime)
        {
            faAnimations.Add(Name, new Animation(x, y, width, height, framecount, mapWidth, frametime));
            spriteWidth = width;
            spriteHeight = height;
            spriteCentre = new Vector2(spriteWidth / 2, spriteHeight / 2);
        }

        /// <summary>
        /// Add a frame of animation to the Dictionary
        /// </summary>
        public void AddAnimation(string Name, int x, int y, int width, int height,
            int framecount, int mapWidth, float frametime, string nextAnim)
        {
            faAnimations.Add(Name, new Animation(x, y, width, height, framecount, mapWidth, frametime, nextAnim));
            spriteWidth = width;
            spriteHeight = height;
            spriteCentre = new Vector2(spriteWidth / 2, spriteHeight / 2);
        }

        /// <summary>
        /// Return an Animation by searching for its String name key
        /// </summary>
        public Animation getAnimation(string Name)
        {
            if (faAnimations.ContainsKey(Name))
            {
                return faAnimations[Name];
            }
            else
            {
                return null;
            }
        }

        public void BasicMove(float VelocityX, float VelocityY)
        {
            PreviousPosition = Position;
            Position.X += VelocityX;
            Position.Y += VelocityY;
            //UpdateRotation();
        }

        public void BasicMove(Vector2 direction)
        {
            PreviousPosition = Position;
            Position += direction;
            //UpdateRotation();
        }

        void UpdateRotation()
        {
            if (rotatable)
            {
                sRotation = (float)Math.Atan2(Position.Y - PreviousPosition.Y,
                                            Position.X - PreviousPosition.X);
            }
            else
            {
                sRotation = 0.0f;
            }
        }

        // Update the Sprite's graphics
        public void Update(GameTime gametime)
        {
            if (animating)
            {
                if (CurrentFrameAnimation == null)
                {
                    if (faAnimations.Count > 0)
                    {
                        // Set the active animation to the first animation
                        // associated with this sprite
                        string[] sKeys = new string[faAnimations.Count];
                        faAnimations.Keys.CopyTo(sKeys, 0);
                        CurrentAnimation = sKeys[0];
                    }
                    else
                    {
                        return;
                    }
                }

                CurrentFrameAnimation.Update(gametime);

                if (!String.IsNullOrEmpty(CurrentFrameAnimation.nextAnimation))
                {
                    // If there is, see if the currently playing animation has
                    // completed a full animation loop
                    if (CurrentFrameAnimation.currentFrame >= CurrentFrameAnimation.frameCount)
                    {
                        // If it has, set up the next animation
                        CurrentAnimation = CurrentFrameAnimation.nextAnimation;
                    }
                }
            }
        }

        // Draw the sprite to the screen
        public void Draw(SpriteBatch theSpriteBatch)
        {
            if (animating)
            {
                theSpriteBatch.Draw(spriteTexture, (Position + spriteCentre),
                               CurrentFrameAnimation.getCurrentSourceRectangle, color,
                               0.0f, spriteCentre, scale, SpriteEffects.None, drawOrder);
            }
        }

        // Draw the sprite to the screen
        public void Draw(SpriteBatch theSpriteBatch, Rectangle temp)
        {
            if (animating && temp != null)
            {
                theSpriteBatch.Draw(spriteTexture, (Position + spriteCentre),
                               temp, color,
                               0.0f, spriteCentre, scale, SpriteEffects.None, drawOrder);
            }
        }
    }
}
